from models import *
from django.views.decorators.cache import never_cache
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response
from django.core import serializers
from django.core.exceptions import ObjectDoesNotExist
from utils import prepare_html_schedule

def index(request):
    """
    Render the index. This is a special case because it doesn't
    come from a URL matching /basicpage/([^/]*)/
    """
    return basicpage(request, 'base')

def basicpage(request, pagename):
    """
    This is for handling requests for 'basic pages', like the
    about us page. It just finds the proper template and renders it.
    """
    allowed = ['base', 'aboutus', 'contactus', 'feedback']
    if pagename not in allowed:
        raise Http404, pagename
    return render_to_response(pagename + '.html', {})

def begin_schedule(request):
    """
    Generate a session ID for this user and redirect
    them to the editor.
    """
    import hashlib
    import random
    session_id = hashlib.sha256(str(random.random())).hexdigest()
    meta_sched = MetaSchedule()
    meta_sched.save()
    user = User(session_id=session_id, meta_schedule=meta_sched)
    user.save()
    request.session['s_id'] = user.session_id
    return HttpResponseRedirect('/editor/')

def editor(request):
    """
    Render the schedule editor. This lets
    users add/remove courses to their MetaSchedule and
    then request the generated schedules.
    """
    if request.session.get('s_id'):
        s_id = request.session['s_id']
        u = User.authenticate(s_id)
        if u:
            import datetime
            semesters = Section.SEMESTER_CHOICES
            timeopts = []
            time_counter = datetime.time(hour=8, minute=0)
            total_blocks = 58
            for i in range(total_blocks):
                timeopts.append(time_counter.strftime('%H:%M'))
                try:
                    time_counter = time_counter.replace(minute=time_counter.minute+15)
                except ValueError:
                    time_counter = time_counter.replace(hour=time_counter.hour + 1, minute=0)

            context = {
                'defaultsemester': 'W',
                'timeopts': timeopts,
                'semesters': semesters,
                'courses': u.meta_schedule.courses.all(),
                'allcourses': Course.objects.all()
            }
            return render_to_response('editor.html', context)
        else:
            return HttpResponseRedirect('/begin/')
    else:
        return HttpResponseRedirect('/begin/')

def add_course_to_schedule(request, c_id):
    """
    A user requests a course with course.id=c_id be added
    to their MetaSchedule. Do it, unless it's already
    there or there are already 6 courses in their MetaSchedule.
    """
    if request.session.get('s_id'):
        s_id = request.session['s_id']
        u = User.authenticate(s_id)
        if u:
            try:
                # Don't let them add more than 6 courses.
                if u.meta_schedule.courses.count() >= 6:
                    message = "You already have 6 courses. It would be foolish to take more!"
                else:
                    c = Course.objects.get(pk=c_id)
                    u.meta_schedule.courses.add(c)
                    u.meta_schedule.save()
                    message = None
                courses = u.meta_schedule.courses.all()
                context = {
                    'courses': courses,
                    'message': message,
                }
                return render_to_response('add_course.html', context)
            except ObjectDoesNotExist:
                return HttpResponse("That course (probably) doesn't even exist!")
        else:
            return HttpResponse("Auth failure.")
    else:
        return HttpResponse("Haven't started a schedule yet (i.e. don't have a user key)")

def remove_course_from_schedule(request, c_id):
    """A user requests that a Course with id=c_id be
    removed from their MetaSchedule. Do it, if it's in there.
    If it's not, well, that would be a silly thing for them
    to try, wouldn't it be?
    """
    if request.session.get('s_id'):
        s_id = request.session['s_id']
        u = User.authenticate(s_id)
        if u:
            try:
                c = u.meta_schedule.courses.get(pk=c_id)
                u.meta_schedule.courses.remove(c)
                u.meta_schedule.save()
                courses = u.meta_schedule.courses.all()
                context = {
                    'courses': courses
                }
                return render_to_response('add_course.html', context)
            except ObjectDoesNotExist:
                return HttpResponse("You haven't even added that course. Looks like there is a problem.")
        else:
            return HttpResponse("Authentication failure.")
    else:
        return HttpResponse("You haven't started a schedule yet (i.e. don't have a user key).")

@never_cache
def generate(request, permid=0):
    """Where the schedule gets generated and sent to the client."""
    if request.session.get('s_id'):
        s_id = request.session['s_id']
        u = User.authenticate(s_id)
        if u:
            if permid is None:
                permid = 0
            # one semester at a time. Specify with ?semester=F on the
            # end of a query
            if request.GET.has_key('semester'):
                # TODO: This is probably not secure
                sem = request.GET['semester']
                semester_code_choices = [c[0] for c in Section.SEMESTER_CHOICES]
                if sem not in semester_code_choices:
                    return HttpResponse("Not a valid semester.")
            else:
                raise Http404

            # parse the preferences and add to the meta_schedule
            # kind of stupid but it works with the design

            # map the parts of the times to integers
            earliest = [int(p) for p in request.GET['earliest'].split(':')]
            latest = [int(p) for p in request.GET['latest'].split(':')]

            # convert them to datetime.times
            import datetime
            earliest_time = datetime.time(hour=earliest[0], minute=earliest[1])
            latest_time = datetime.time(hour=latest[0], minute=latest[1])

            # save them to the preferencesfilter
            p = PreferencesFilter()
            p.earliest_class_start = earliest_time
            p.latest_class_end = latest_time
            p.save()
            u.meta_schedule.prefs = p
            u.meta_schedule.save()

            # actually generate the schedule
            iternum = u.meta_schedule.generate(int(permid), sem)
            r = HttpResponse("")
            link_to_last_schedule = "<a class='prev-schedule' href='/generate/%d/'>Go to the last schedule</a>" % (int(permid)-1)

            errormesg = "<br/><br/>No additional schedules (or none at all) could be found with those courses and time constraints.<br/>"
            if iternum is False:
                r.write(errormesg + link_to_last_schedule)
            else:
                all_scheds = u.meta_schedule.schedules.all()
                if len(all_scheds) > 0:
                    sched = all_scheds[0]
                    r.write(prepare_html_schedule(sched, iternum))
                else:
                    r.write(errormesg + link_to_last_schedule)
            return r
